<template>
  <div class="app-container">
    <template>
      <el-tabs v-model="activeName">
        <el-tab-pane label="SM2-SM3" name="first">
          <el-row :gutter="20">
            <el-col :span="10">
              <el-form
                ref="form"
                :model="form"
                label-width="40px"
                :inline="true"
              >
                <el-form-item>
                  <el-button @click="generateKeyPairHex" type="success">
                    生成SM2密钥对
                  </el-button>
                </el-form-item>
                <el-form-item label="公钥">
                  <el-input
                    v-model="form.publicKey"
                    type="textarea"
                    :autosize="{ minRows: 6, maxRows: 6 }"
                    placeholder="请输入或生成公钥"
                  />
                </el-form-item>
                <el-form-item label="私钥">
                  <el-input
                    v-model="form.privateKey"
                    type="textarea"
                    :autosize="{ minRows: 4, maxRows: 4 }"
                    placeholder="请输入或生成私钥"
                  />
                </el-form-item>
                <el-input
                  v-model="form.inputString"
                  type="textarea"
                  :autosize="{ minRows: 20, maxRows: 20 }"
                  placeholder="请输入需要加密的字符串"
                />
              </el-form>
            </el-col>
            <el-col :span="3">
              <el-form ref="form" :model="form">
                <el-divider content-position="left">
                  <span style="font-weight: bolder">SM2加密解密</span>
                </el-divider>
                <el-form-item label="选择加密模式">
                  <el-radio-group v-model="form.cipherMode">
                    <el-radio :label="0">c1-c2-c3</el-radio>
                    <el-radio :label="1">c1-c3-c2</el-radio>
                  </el-radio-group>
                </el-form-item>
                <el-form-item>
                  <el-button @click="sm2Encrypt" type="success">加密</el-button>
                  <el-button @click="sm2Decrypt" type="primary">解密</el-button>
                </el-form-item>
                <el-divider content-position="left">
                  <span style="font-weight: bolder">SM2签名验签</span>
                </el-divider>
                <el-form-item>
                  <el-button @click="sm2Sign" type="success">签名</el-button>
                  <el-button @click="sm2VerifySign" type="primary">
                    验签
                  </el-button>
                </el-form-item>
                <el-divider content-position="left">
                  <span style="font-weight: bolder">SM3</span>
                </el-divider>
                <el-form-item>
                  <el-button @click="sm3Hash" type="success">杂凑</el-button>
                </el-form-item>
              </el-form>
              <div></div>
            </el-col>
            <el-col :span="10">
              <div>
                <el-divider content-position="left">
                  <span style="font-weight: bolder">加密结果</span>
                </el-divider>
                <el-input
                  v-model="form.outputString"
                  type="textarea"
                  :autosize="{ minRows: 5, maxRows: 5 }"
                  placeholder="请输入需要解密的字符串"
                />
                <el-divider content-position="left">
                  <span style="font-weight: bolder">签名结果</span>
                </el-divider>
                <el-input
                  v-model="form.signString"
                  type="textarea"
                  :autosize="{
                    minRows: 5,
                    maxRows: 5,
                  }"
                  placeholder="请输入需要验签的字符串"
                />
                <el-divider content-position="left">
                  <span style="font-weight: bolder">杂凑结果</span>
                </el-divider>
                <el-input
                  v-model="form.sm3String"
                  type="textarea"
                  :autosize="{ minRows: 5, maxRows: 5 }"
                />
              </div>
            </el-col>
          </el-row>
        </el-tab-pane>
        <el-tab-pane label="SM4" name="second">
          <el-row :gutter="20">
            <el-col :span="10">
              <el-input
                placeholder="请输入或生成密钥，16 进制串，要求为 128 比特"
                v-model="sm4form.publicKey"
              >
                <el-button
                  slot="append"
                  icon="el-icon-thumb"
                  @click="generateKey"
                >
                  生成密钥
                </el-button>
              </el-input>
              <br />
              <br />
              <el-input
                placeholder="请输入或生成密钥，字节数组，要求为 128 比特"
                v-model="showArrPublicKey"
              >
              </el-input>
              <el-divider> </el-divider>
              <el-input
                v-model="sm4form.inputString"
                type="textarea"
                :autosize="{ minRows: 20, maxRows: 20 }"
                placeholder="请输入需要加密的字符串"
              />
            </el-col>
            <el-col :span="3">
              <el-form ref="sm4form">
                <el-form-item label="请选择：">
                  <el-checkbox v-model="sm4form.isArray"
                    >输出字节数组</el-checkbox
                  >
                  <el-checkbox v-model="sm4form.isCBC">CBC模式加密</el-checkbox>
                </el-form-item>
                <el-form-item v-if="sm4form.isCBC" label="iv值(上一轮加密结果)">
                  <el-input v-model="sm4form.iv" placeholder="请输入密钥" />
                </el-form-item>
                <el-form-item>
                  <el-button @click="sm4Encrypt" type="success">加密</el-button>
                  <el-button @click="sm4Decrypt" type="primary">解密</el-button>
                </el-form-item>
              </el-form>
            </el-col>
            <el-col :span="10">
              <div>
                <el-divider content-position="left">
                  <span style="font-weight: bolder">原始加密结果</span>
                </el-divider>
                <el-input
                  v-model="sm4form.outputString"
                  type="textarea"
                  :autosize="{ minRows: 5, maxRows: 5 }"
                  placeholder="请输入需要解密的字符串"
                />
                <el-divider content-position="left">
                  <span style="font-weight: bolder">数组加密结果</span>
                </el-divider>
                <el-input
                  v-model="showOutputArr"
                  type="textarea"
                  :autosize="{
                    minRows: 5,
                    maxRows: 5,
                  }"
                  placeholder="请输入需要解密的数组"
                />
                <el-divider content-position="left">
                  <span style="font-weight: bolder">CBC加密结果</span>
                </el-divider>
                <el-input
                  v-model="sm4form.cbcOutputString"
                  type="textarea"
                  :autosize="{ minRows: 5, maxRows: 5 }"
                  placeholder="CBC加密结果"
                />
              </div>
            </el-col>
          </el-row>
        </el-tab-pane>
      </el-tabs>
    </template>
  </div>
</template>

<script>
import { sm2, sm3, sm4 } from "sm-crypto";
export default {
  name: "SM",
  computed: {
    showArrPublicKey: {
      get: function () {
        return this.sm4form.arrPublicKey.toString();
      },
      set: function (val) {
        this.sm4form.arrPublicKey = val.split(",");
      },
    },
    showOutputArr: {
      get: function () {
        return this.sm4form.outputArr.toString();
      },
      set: function (val) {
        this.sm4form.outputArr = val.split(",");
      },
    },
    // getPoint: {
    //   get: function () {
    //     console.log(sm2.getPoint());
    //     return sm2.getPoint();
    //   },
    // },
  },
  data() {
    return {
      activeName: "first",
      form: {
        publicKey: "",
        privateKey: "",
        inputString: "",
        cipherMode: 0, // 1 - C1C3C2，0 - C1C2C3，默认为1
        outputString: "",
        verifyResult: "",
        signString: "",
        sm3String: "",
      },
      sm4form: {
        publicKey: "",
        arrPublicKey: [],
        inputString: "",
        outputString: "",
        outputArr: [],
        cbcOutputString: "",
        isArray: false,
        isCBC: false,
        iv: "",
      },
    };
  },
  methods: {
    generateKeyPairHex() {
      let keypair = sm2.generateKeyPairHex();
      this.form.publicKey = keypair.publicKey; // 公钥
      this.form.privateKey = keypair.privateKey; // 私钥
    },
    sm2Encrypt() {
      try {
        this.form.outputString = sm2.doEncrypt(
          this.form.inputString,
          this.form.publicKey,
          this.form.cipherMode
        ); // 加密结果
      } catch (error) {
        this.$alert("信息填写错误", "加密", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
    },
    sm2Decrypt() {
      try {
        this.form.inputString = sm2.doDecrypt(
          this.form.outputString,
          this.form.privateKey,
          this.form.cipherMode
        ); // 解密结果
      } catch (error) {
        this.$alert("信息填写错误", "解密", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
    },
    sm2Sign() {
      try {
        this.form.signString = sm2.doSignature(
          this.form.inputString,
          this.form.privateKey
        );
      } catch (error) {
        this.$alert("信息填写错误", "签名", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
      // 签名
    },
    sm2VerifySign() {
      // 验签
      try {
        this.form.verifyResult = sm2.doVerifySignature(
          this.form.inputString,
          this.form.signString,
          this.form.publicKey
        );
      } catch (error) {
        this.$alert("信息填写错误", "验签", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
      this.$alert(`验签结果为：${this.form.verifyResult}`, "验签", {
        confirmButtonText: "确定",
        type: this.form.verifyResult ? "success" : "error",
      });
    },
    sm3Hash() {
      try {
        this.form.sm3String = sm3(this.form.inputString);
      } catch (error) {
        this.$alert("信息填写错误", "杂凑", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
    },
    generateKey() {
      const arr = "0123456789abcdef".split("");
      let key = "";
      for (let index = 0; index < 32; index++) {
        key += arr[Math.floor(Math.random() * 16)];
      }
      this.sm4form.publicKey = key;
      this.sm4form.arrPublicKey = this.hexToArray(key);
    },
    sm4Encrypt() {
      try {
        this.sm4form.outputString = sm4.encrypt(
          this.sm4form.inputString,
          this.sm4form.publicKey || this.sm4form.arrPublicKey
        ); // 加密结果
        if (this.sm4form.isArray) {
          this.sm4form.outputArr = sm4.encrypt(
            this.sm4form.inputString,
            this.sm4form.publicKey || this.sm4form.arrPublicKey,
            {
              output: "array",
            }
          );
        }
        if (this.sm4form.isCBC) {
          this.sm4form.cbcOutputString = sm4.encrypt(
            this.sm4form.inputString,
            this.sm4form.publicKey,
            { mode: "cbc", iv: this.sm4form.iv }
          ); // 加密结果
        }
      } catch (error) {
        this.$alert("信息填写错误", "加密", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
    },
    sm4Decrypt() {
      try {
        this.sm4form.inputString = sm4.decrypt(
          this.sm4form.outputString || this.sm4form.outputArr,
          this.sm4form.publicKey || this.sm4form.arrPublicKey
        ); // 解密结果
        if (this.sm4form.isCBC) {
          this.sm4form.inputString = sm4.decrypt(
            this.sm4form.cbcOutputString,
            this.sm4form.publicKey || this.sm4form.arrPublicKey,
            { mode: "cbc", iv: this.sm4form.iv }
          ); // 解密结果
        }
      } catch (error) {
        this.$alert("信息填写错误", "解密", {
          confirmButtonText: "确定",
          type: "error",
        });
      }
    },
    hexToArray(str) {
      const arr = [];
      for (let i = 0, len = str.length; i < len; i += 2) {
        arr.push(parseInt(str.substr(i, 2), 16));
      }
      return arr;
    },
  },
};
</script>

<style scoped>
.box {
  border: gray 1px solid;
  font-weight: bolder;
}
</style>
